package com.wanban.downloader.mp4

import android.text.TextUtils
import android.util.Log
import com.blankj.utilcode.util.CloseUtils
import com.blankj.utilcode.util.ThreadUtils
import com.wanban.downloader.BuildConfig
import com.wanban.downloader.db.DatabaseUtils
import com.wanban.downloader.db.DownloadEntity
import com.wanban.downloader.exception.HttpConnectionException
import com.wanban.downloader.http.HttpConnectUtils
import com.wanban.downloader.listener.OnBaseDownloadListener
import com.wanban.downloader.listener.OnM3U8DownloadListener
import com.wanban.downloader.model.DownloadParams
import com.wanban.downloader.model.M3U8Seg
import com.wanban.downloader.utils.FileDownloadPathUtils
import kotlinx.coroutines.Deferred
import java.io.RandomAccessFile
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit


class Mp4DownloadUtils(val task: DownloadEntity, val listener: OnM3U8DownloadListener): OnBaseDownloadListener {

    private val TAG = "Mp4下载"
    // 回调时间间隔
    private var interval = 1000
    // 当前视频ts总个数
    private var totalLength = 0L
    // 每次数据更新后的时间
    private var callbackTime = 0L
    // 已下载文件大小
    private var currentFileLength = 0L
    // 当前速度，即 #interval 时间范围内的下载量
    private var updateProgressLength = 0L
    // 是否中断任务执行
    @Volatile
    private var interrupted = false
    // ts下载目录
    private var mp4FileRootPath: String? = null
    private val runningTask by lazy { ArrayList<Deferred<Boolean>>() }
    // 通过 构造方法 配置核心参数
    private val executor by lazy {
        ThreadPoolExecutor(DownloadParams.maxThreadNumber, DownloadParams.maxThreadNumber,
            0L, TimeUnit.MILLISECONDS,
             LinkedBlockingQueue<Runnable>()
        )
    }

    init {
        startDownloadMp4()
    }

    private fun startDownloadMp4(){
        try {
            interrupted = false
            if (task.m3u8?.tsList.isNullOrEmpty()) {
                if (interrupted) return
                listener.onError(task.url, "Mp4下载数据出错!")
                return
            }
            // 先创建下载目录文件
            mp4FileRootPath = FileDownloadPathUtils.getMp4FilePath(task.fileDirPath)
            if (TextUtils.isEmpty(mp4FileRootPath)) {
                if (interrupted) return
                listener.onError(task.url, "创建mp4FileDirPath失败")
                return
            }
            Log.d(TAG, "${task.getFileName()} -> 准备下载mp4...")
            if (interrupted) return
            totalLength = (task.m3u8?.tsList?.lastOrNull()?.mp4EndIndex?:0L) + 1
            // 回调准备开始下载
            listener.onStart(task.url)
            val totalThreadCount = task.m3u8?.tsList?.size?:0
            task.m3u8?.tsList?.forEachIndexed { index, mp4Fragment ->
                Log.e(TAG, "第" + (index + 1) + "个线程的下载区间为:" + mp4Fragment.mp4StartIndex + "-" + mp4Fragment.mp4EndIndex)
                currentFileLength += mp4Fragment.contentLength
                excProgress(currentFileLength.toInt())
                val downloadTask = object: ThreadUtils.Task<M3U8Seg>() {
                    override fun doInBackground(): M3U8Seg {
                        return downloadFile(mp4Fragment)
                    }

                    override fun onCancel() {

                    }

                    override fun onFail(t: Throwable?) {
                        if (interrupted || t is InterruptedException) return
                        cancelAllTask()
                        listener.onError(task.url, t?.message?:"下载内部出现异常！")
                    }

                    override fun onSuccess(result: M3U8Seg?) {
                        if (interrupted) return
                        if (totalThreadCount == executor.completedTaskCount.toInt()) {
                            task.filePath = mp4FileRootPath
                            Log.e(TAG, "${task.getFileName()} -> 下载循环执行完成...")
                            listener.onSuccess(task)
                        }
                    }
                }
                // 执行任务
                executor.submit(downloadTask)
            }
        } catch (e: Exception) {
            if (interrupted || e is InterruptedException) return
            e.printStackTrace()
            listener.onError(task.url, e.message?:"下载内部出现异常")
        }
    }

    private fun downloadFile(mp4Fragment: M3U8Seg): M3U8Seg{
        val headerMap = if (task.header == null) HashMap() else task.header!!
        headerMap["RANGE"] = "bytes=${mp4Fragment.mp4StartIndex}-${mp4Fragment.mp4EndIndex}"
        // 开始请求连接
        val response = HttpConnectUtils().open(task.url, httpHeaders = headerMap)
        if (interrupted) return mp4Fragment
        if (response == null) {
            listener.onError(task.url, "下载链接请求失败！")
            return mp4Fragment
        }
        val inputStream = response.body?.byteStream()
        if (interrupted) return mp4Fragment
        if (inputStream == null) {
            listener.onError(task.url, "下载链接请求失败！")
            return mp4Fragment
        }
        var randomAccessFile: RandomAccessFile? = null
        try {
            randomAccessFile = RandomAccessFile(mp4FileRootPath, "rw")
            randomAccessFile.seek(mp4Fragment.contentLength)
            if (interrupted) return mp4Fragment
            var bytesRead: Int
            val buffer = ByteArray(4096)
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                if (interrupted) break
                randomAccessFile.write(buffer, 0, bytesRead)
                currentFileLength += bytesRead
                mp4Fragment.contentLength += bytesRead
                excProgress(bytesRead)
            }
            mp4Fragment.complete = true
            return mp4Fragment
        } catch (e: Exception) {
            if (interrupted || e is InterruptedException) return mp4Fragment
            e.printStackTrace()
            val message = if (BuildConfig.DEBUG) e.message?:"下载失败！" else "下载失败！"
            throw HttpConnectionException(message)
        } finally {
            CloseUtils.closeIOQuietly(randomAccessFile, inputStream)
        }
    }


    override fun cancelAllTask() {
        interrupted = true
        // 回调时间间隔
        interval = 0
        // 当前视频ts总个数
        totalLength = 0
        // 每次数据更新后的时间
        callbackTime = 0L
        // 已下载文件大小
        currentFileLength = 0L
        // 当前速度，即 #interval 时间范围内的下载量
        updateProgressLength = 0L
        runningTask.forEach {
            if (!it.isCancelled) {
                it.cancel()
            }
        }
        runningTask.clear()
        // ts下载目录
        mp4FileRootPath = null
    }

    private fun excProgress(len: Int){
        updateProgressLength += len
        if (System.currentTimeMillis() > callbackTime + interval && !interrupted) {
            listener.onProgress(task.url, updateProgressLength, currentFileLength * 100f / totalLength, totalLength)
            callbackTime = System.currentTimeMillis()
            updateProgressLength = 0L
            DatabaseUtils.insertOrUpdateTask(task) {}
        }
    }

}



